/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package business;

import entity.Event;
import entity.Group;
import java.security.Principal;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import entity.User;
import entity.Visibility;
import entity.Group;
import entity.Message;
import entity.Participant;
import entity.SentMessage;
import exceptions.DuplicateUserException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.persistence.NamedQuery;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

/**
 * This bean handles the functionalities provided to the user + load the
 * calendar
 *
 * @author Alessandro
 */
@Stateless
public class UserManager implements Serializable {

    @PersistenceContext
    public EntityManager em;

    @Inject
    Principal principal;

    /**
     * register an user in the DB
     *
     * @param user the user to be saved
     * @return 
     * @throws 
     */
    public void save(User user) throws DuplicateUserException {
        user.setGroupName(Group.USER);
        user.setVisibility(Visibility.PRIVATE);
        if (canRegister(user)) {
            em.persist(user);
        }else{
            throw new DuplicateUserException();
        } 
        
    }
    
    public boolean canRegister(User user){
        if(em.find(User.class, user.getEmail())==null){
            return true;
        }else{
            return false;
        }
    }

    /**
     *
     * @return the logged user in this session
     */
    public User getLoggedUser() {
        return em.find(User.class, principal.getName());
    }

    /**
     * this method modifies the calendar visibilty of an user
     *
     * @return a string that is the profile page
     */
    public void changeVisibility() {
        User user = this.getLoggedUser();
        System.out.println("ciao, sono user manager, cambio visibilita che per ora è" + user.getVisibility());
        Query vis = em.createNamedQuery("changeVisibility2");
        if (user.getVisibility().equals(Visibility.PUBLIC)) {
            vis.setParameter("visibility", Visibility.PRIVATE);
        } else {
            vis.setParameter("visibility", Visibility.PUBLIC);
        }
        vis.setParameter("email", user.getEmail());
        vis.executeUpdate();
    }

    /**
     * this method load in a list all the events of an user
     *
     * @return a list of user's events
     */
    public List<Event> loadCalendar() {
        System.out.println("adesso flusho");
        em.flush();

        /* 
         dunno why???!! need this coz it won't update the events created in the same session
         Actually, this line refresh the EntityManager cache, in order to show the new modification
         in the list
         */
        em.getEntityManagerFactory().getCache().evictAll();
        User user = this.getLoggedUser();
        System.out.println("ciao, sono user manager, carico eventi per " + user.getEmail());
        // get all the participart tuple of this specific user
        Collection<Participant> cal = user.getParticipantCollection();
        List<Event> calendar = new ArrayList<>();
        for (Participant p : cal) {
            //Control that deleted events are not added to the list.
            if (!p.getEvent1().isDeleted()) {
                calendar.add(p.getEvent1());
            }
        }
        System.out.println("lista prima_ " + calendar.toString());
        calendar.sort(null);
        System.out.println("lista dopo_ " + calendar.toString());

        return calendar;
    }

    /**
     * This is the function that load the messages of the logged user.
     *
     * @return the list of messages.
     *
     * public List<Message> loadMessages() { em.flush();
     * em.getEntityManagerFactory().getCache().evictAll();
     *
     * System.out.println("caricameto messagi"); Collection<SentMessage>
     * messageList = this.getLoggedUser().getSentMessageCollection();
     * List<Message> userMessages = new ArrayList<>(); for (SentMessage sm :
     * messageList) { userMessages.add(sm.getMessage1()); } return userMessages;
     * }
     */
    /**
     * This is the function that load the sentMessages for a user, that is the
     * list of tuples saying which messages a user received and if they are
     * pending or already been read.
     *
     * @return the list of sentMessages.
     */
    public List<SentMessage> loadSentMessages() {
        em.flush();
        em.getEntityManagerFactory().getCache().evictAll();

        List<SentMessage> sentMessages = new ArrayList<>();
        sentMessages.addAll(this.getLoggedUser().getSentMessageCollection());
        sentMessages.sort(null);
        return sentMessages;

    }

    /**
     * The function that modify the message status and make it persistent.
     *
     * @param message
     */
    public void readMessage(SentMessage message) {
        System.out.println("user manager : Ho letto il messaggio " + message.toString());
        message.setPending(false);
        em.merge(message);
    }

    /**
     * Check how much messages the user has in its list not yet read
     *
     * @return the number of not-read messages
     */
    public int checkPendingMessages() {
        TypedQuery<SentMessage> findNotReadMessages = em.createQuery("SELECT sm FROM SentMessage sm WHERE (sm.user1 = :user AND sm.pending = 1)", SentMessage.class);
        findNotReadMessages.setParameter("user", this.getLoggedUser());
        return findNotReadMessages.getResultList().size();
    }

    /**
     * The function loading the events of a given user. The caller bean is in
     * charge of not showing private events. If the user has a private calendar,
     * the function returns an empty list.
     *
     * @param email the email of the user we want to retrieve the events
     * @return the list of events the user is participating to, or he has
     * created
     */
    public List<Event> loadUserCalendar(String email) {
        List<Event> userCalendar = new ArrayList();
        //Query to retrieve the target user.
        TypedQuery<User> findUserPerEmail = em.createQuery("SELECT u FROM User u WHERE (u.email = :email)", User.class);
        findUserPerEmail.setParameter("email", email);
        System.out.println("sono user manager cercando utente : " + email);
        User targetUser = findUserPerEmail.getResultList().get(0);
        //If the user a private calendar, do nothing.
        System.out.println("adesso vedo se ha il calendario privato");

        if (targetUser.getVisibility().equals(Visibility.PUBLIC)) {
            System.out.println("è pubblico");

            Collection<Participant> userParticipants = targetUser.getParticipantCollection();
            for (Participant p : userParticipants) {
                if (p.getAnswer().equals("yes")) {
                    userCalendar.add(p.getEvent1());
                }
            }
            return userCalendar;
        }
        System.out.println("è privato");

        return null;
    }
}
